通过源码发现nltk.Text.similar相似度衡量标准 |
您所在的位置:网站首页 › similar to 和similar in › 通过源码发现nltk.Text.similar相似度衡量标准 |
1. 如何用nltk来找到text中相似的word
如果我们想搜索某一篇文章(text)中相似的词(word),可以使用nltk这个强大的NLP模块。下面以nltk自带的shakespeare数据集来做示例。 第一次使用nltk,需要先运行下面的代码来下载shakespeare数据集。 import nltk nltk.download('shakespeare')然后,我们就可以加载shakespeare数据集来做实验了: import nltk text = nltk.Text(word.lower() for word in nltk.corpus.shakespeare.words(('hamlet.xml')))只要使用nltk.Text.similar(word),就能找到text中跟某个word相似的其他所有word了,如下示例 text.similar('woman')我们就能得到与woman相似的所有词: matter at eaten but fit this to vulcan by like servant disclose follows twice laertes it cat such sin可以看到,这些输出的词中,有的确实与woman有一点点相似,比如“vulcan”和“servant”。但还有大量的词是与woman没有任何关系的,比如“twice”。 那问题来了,nltk.Text.similar是根据什么来衡量两个词的相似度呢? 2. nltk.Text.similar源码网上并没有太多关于nltk.Text.similar的原理解释,所以只有查阅源码,才能看到细节。 nltk.Text.similar的源码在https://github.com/nltk/nltk/blob/develop/nltk/text.py,其中有一个函数similar(self, word, num=20),这就是nltk.Text.similar的实现,核心代码如下: def similar(self, word, num=20): """ Distributional similarity: find other words which appear in the same contexts as the specified word; list most similar words first. :param word: The word used to seed the similarity search :type word: str :param num: The number of words to generate (default=20) :type num: int :seealso: ContextIndex.similar_words() """ word = word.lower()# 统一转换为小写进行比较 wci = self._word_context_index._word_to_contexts if word in wci.conditions(): # 根据上下文context相同来查找其它词 contexts = set(wci[word]) fd = Counter( w for w in wci.conditions() for c in wci[w] if c in contexts and not w == word ) # most_common是根据出现次数从到到低来输出 words = [w for w, _ in fd.most_common(num)] print(tokenwrap(words))从源码中,我们可以看到, nltk.Text.similar是用Distributional similarity来衡量两个word是否相似。Distributional similarity的做法,首先找到与给定词(the specified word)具有相同上下文(same context)的所有词,然后根据这些词的出现次数,按出现次数从高到低依次输出(most similar words first)。 举个例子,假如有如下一篇文档: C3 W4 C4 C1 W3 C2 C1 W3 C2 C1 W3 C2 C1 W2 C2 C1 W2 C2 C1 W1 C2 C1 W C2与词W有相同上下文(C1 X C2)的,是词W1,W2,W3。但W3出现了3次,W2出现了2次,所以W3先输出,W2后输出。 通过阅读nltk.Text.similar源码,我们理解了它判断两个word是否相似,是根据上下文来判断,而非我们人理解的相似度。因为nltk.Text.similar根据上下文,只能找到相似,或不相似的词,所以也就无法做量化的相似度衡量(比如W1与W2相似度为0.8)。 我们再来人为构建几个例子,通过实例深入理解nltk.Text.similar。 3. 上下文similar实例通过如下代码,我们可以找到语料s中与boy相似的其它词。 import nltk s = '''A B C boy D E F G A B C dog D E F G A B C cat D E F G A A A man B B B B ''' tokens = nltk.word_tokenize(s) text = nltk.Text(tokens) text.similar('boy')可以得到结果为“cat dog”,这个容易理解,应为“cat”和“dog”的上下文(A B C X D E F G)与“boy”相同。预料中的“man”虽然逻辑上与“boy”应该更具有相似性,但应为nltk.Text.similar是根据上下文来判断相似性,而不是根据逻辑来判断相似性,所以输出结果中没有“man”。 根据源码中similar()的定义similar(self, word, num=20),我们还发现similar()的另一个参数num,它默认是20,指的是输出20个与给定词相似的词,我们将本例中的代码更改为num=1,即text.similar('boy',1),则输出只有1个词“cat”。 本例中,boy的上下文为"A B C" 与 “D E F G”,那similar()在进行相似度搜索是,是完全根据"A B C" 与 "D E F G"都相同才算相似词吗?还是上下文有一个搜索长度的限制,比如只考虑boy之前的3个单词和与之后的3个单词?我发现源码中并无类似的参数,所以设计了如下实验来进行验证。 4. 上下文的长度是多少?下面是改动了各个词相似的上下文(单词)长度,用来测试上下文长度的例子(查找语料s中与boy相似的词): import nltk s = '''A B C boy D E F G C dog D A B B cat D E F G A A c man d B B B ''' tokens = nltk.word_tokenize(s) text = nltk.Text(tokens) text.similar('boy')代码的输出是“dog man”,所以我们得到两个结论 上下文,只考虑待搜索词的前一个词和后一个词,即boy(上下文为C X D)与dog(上下文为C X D)相似 上下文搜索时,不考虑大小写,即boy(上下文为C X D)与man(上下文为c X d)相似 5. 参考 How to load and analysis corpus shakespeare Understand nltk.Text.similarnltk source code here |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |